package com.gobang.modules.netty;

import com.gobang.modules.message.MessageTypeCategory;
import com.gobang.modules.message.MsgDispatcher;
import com.gobang.modules.game.GameService;
import com.gobang.modules.match.MatchService;
import com.gobang.modules.message.MessageService;
import com.gobang.modules.player.PlayerService;
import com.gobang.proto.GameProto.*;
import com.google.protobuf.InvalidProtocolBufferException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * WebSocket处理器
 * 职责：仅负责网络连接管理和消息路由
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Autowired
    private PlayerService playerService;
    @Autowired
    private MatchService matchService;
    @Autowired
    private GameService gameService;
    @Autowired
    private MessageService messageService;

    // 消息分发器 - 自动路由到带@MsgHandler注解的方法
    @Autowired
    private MsgDispatcher msgDispatcher;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
        if (frame instanceof BinaryWebSocketFrame) {
            handleBinaryFrame(ctx, (BinaryWebSocketFrame) frame);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        Long userId = playerService.removePlayer(ctx);
        if (userId != null) {
            matchService.cancelMatch(userId);
            gameService.handlePlayerDisconnect(userId);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("连接异常", cause);
        ctx.close();
    }

    private void handleBinaryFrame(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) {
        ByteBuf buf = frame.content();
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);

        try {
            GameMessage message = GameMessage.parseFrom(bytes);
            handleGameMessage(ctx, message);
        } catch (InvalidProtocolBufferException e) {
            log.error("解析消息失败", e);
        }
    }

    /**
     * 处理游戏消息 - 通过MsgDispatcher自动分发到带@MsgHandler注解的方法
     * 统一验证登录状态：登录后的消息需要验证用户是否已登录
     */
    private void handleGameMessage(ChannelHandlerContext ctx, GameMessage message) {
        try {
            MessageType type = message.getType();
            
            // 如果是登录后的消息，统一验证登录状态
            if (!MessageTypeCategory.isPreLoginMessage(type)) {
                Long userId = playerService.getUserId(ctx);
                if (userId == null) {
                    log.warn("未登录用户尝试访问登录后功能: type={}", type);
                    messageService.sendError(ctx, 401, "未登录，请先登录");
                    return;
                }
            }
            
            // 验证通过，分发消息到对应的处理器
            msgDispatcher.dispatch(ctx, message);
        } catch (Exception e) {
            log.error("处理消息失败: type={}", message.getType(), e);
            messageService.sendError(ctx, 500, "服务器内部错误");
        }
    }

}
